// Package service @author dingrui @since 2021/11/26
package service

import (
	"encoding/json"
	"log"
	"strconv"
	"strings"

	"github.com/bannirui/mini-prize/common"
	"github.com/bannirui/mini-prize/dal/dao"
	"github.com/bannirui/mini-prize/dal/model"
	"github.com/bannirui/mini-prize/datasource"
	"github.com/bannirui/mini-prize/dto"
)

var (
	// 单例
	G_giftService GiftService
)

type GiftService interface {
	GetAll(useCache bool) []model.Gift
	CountAll() int64
	Get(id int, useCache bool) *model.Gift
	Delete(id int) error
	Update(data *model.Gift, columns []string) error
	Create(data *model.Gift) error
	GetAllUse(useCache bool) []dto.GiftDTO
	IncrLeftNum(id, num int) (int64, error)
	DecrLeftNum(id, num int) (int64, error)
}

type giftService struct {
	dao *dao.GiftDao
}

func init() {
	G_giftService = &giftService{dao: dao.G_giftDao}
}

func (s *giftService) GetAll(useCache bool) []model.Gift {
	if !useCache {
		// 直接读取数据库的方式
		return s.dao.ListAll()
	}

	// 先读取缓存
	gifts := s.getAllByCache()
	if len(gifts) < 1 {
		// 再读取数据库
		gifts = s.dao.ListAll()
		s.setAllByCache(gifts)
	}
	return gifts
}

func (s *giftService) CountAll() int64 {
	// 直接读取数据库的方式
	// return s.dao.CountAll()

	// 缓存优化之后的读取方式
	gifts := s.GetAll(true)
	return int64(len(gifts))
}

func (s *giftService) Get(id int, useCache bool) *model.Gift {
	if !useCache {
		// 直接读取数据库的方式
		return s.dao.GetById(id)
	}

	// 缓存优化之后的读取方式
	gifts := s.GetAll(true)
	for _, gift := range gifts {
		if gift.Id == id {
			return &gift
		}
	}
	return nil
}

func (s *giftService) Delete(id int) error {
	// 先更新缓存
	data := &model.Gift{Id: id}
	s.updateByCache(data, nil)
	// 再更新数据库
	return s.dao.DeleteById(id)
}

func (s *giftService) Update(data *model.Gift, columns []string) error {
	// 先更新缓存
	s.updateByCache(data, columns)
	// 再更新数据库
	return s.dao.Update(data, columns)
}

func (s *giftService) Create(data *model.Gift) error {
	// 先更新缓存
	s.updateByCache(data, nil)
	// 再更新数据库
	return s.dao.InsertOne(data)
}

// 获取到当前可以获取的奖品列表
// 有奖品限定，状态正常，时间期间内
// gtype倒序， displayorder正序
func (s *giftService) GetAllUse(useCache bool) []dto.GiftDTO {
	list := make([]model.Gift, 0)
	if !useCache {
		// 直接读取数据库的方式
		list = s.dao.ListAllAvailable()
	} else {
		// 缓存优化之后的读取方式
		now := common.NowUnix()
		gifts := s.GetAll(true)
		for _, gift := range gifts {
			if gift.Id > 0 && gift.Status == 0 &&
				gift.TotalCnt >= 0 &&
				gift.BeginTime <= now &&
				gift.EndTime >= now {
				list = append(list, gift)
			}
		}
	}

	if list != nil {
		gifts := make([]dto.GiftDTO, 0)
		for _, gift := range list {
			codes := strings.Split(gift.HitRate, "-")
			if len(codes) == 2 {
				// 设置了获奖编码范围 a-b 才可以进行抽奖
				codeA := codes[0]
				codeB := codes[1]
				a, e1 := strconv.Atoi(codeA)
				b, e2 := strconv.Atoi(codeB)
				if e1 == nil && e2 == nil && b >= a && a >= 0 && b < 10000 {
					data := dto.GiftDTO{
						Id:           gift.Id,
						Title:        gift.Name,
						PrizeNum:     gift.TotalCnt,
						LeftNum:      gift.RemainCnt,
						PrizeCodeA:   a,
						PrizeCodeB:   b,
						Img:          gift.Img,
						Displayorder: gift.DispOrder,
						Gtype:        gift.Type,
						Gdata:        gift.Data,
					}
					gifts = append(gifts, data)
				}
			}
		}
		return gifts
	} else {
		return []dto.GiftDTO{}
	}
}

func (s *giftService) IncrLeftNum(id, num int) (int64, error) {
	return s.dao.IncrRemainCnt(id, num)
}

func (s *giftService) DecrLeftNum(id, num int) (int64, error) {
	return s.dao.DecrLeftNum(id, num)
}

// 从缓存中获取全部的奖品
func (s *giftService) getAllByCache() []model.Gift {
	// 集群模式，redis缓存
	key := "allgift"
	// 读取缓存
	rs, err := datasource.G_redis.Do("GET", key)
	if err != nil {
		log.Println("gift_service.getAllByCache GET key=", key, ", error=", err)
		return nil
	}
	str := common.GetString(rs, "")
	if str == "" {
		return nil
	}
	// 将json数据反序列化
	datalist := []map[string]interface{}{}
	err = json.Unmarshal([]byte(str), &datalist)
	if err != nil {
		log.Println("gift_service.getAllByCache json.Unmarshal error=", err)
		return nil
	}
	// 格式转换
	gifts := make([]model.Gift, len(datalist))
	for i := 0; i < len(datalist); i++ {
		data := datalist[i]
		id := common.GetInt64FromMap(data, "Id", 0)
		if id <= 0 {
			gifts[i] = model.Gift{}
		} else {
			gift := model.Gift{
				Id:          int(id),
				Name:        common.GetStringFromMap(data, "Name", ""),
				TotalCnt:    int(common.GetInt64FromMap(data, "TotalCnt", 0)),
				RemainCnt:   int(common.GetInt64FromMap(data, "RemainCnt", 0)),
				HitRate:     common.GetStringFromMap(data, "HitRate", ""),
				DurationDay: int(common.GetInt64FromMap(data, "DurationDay", 0)),
				Img:         common.GetStringFromMap(data, "Img", ""),
				DispOrder:   int(common.GetInt64FromMap(data, "DispOrder", 0)),
				Type:        int(common.GetInt64FromMap(data, "Type", 0)),
				Data:        common.GetStringFromMap(data, "Data", ""),
				BeginTime:   int(common.GetInt64FromMap(data, "BeginTime", 0)),
				EndTime:     int(common.GetInt64FromMap(data, "EndTime", 0)),
				DispBegin:   int(common.GetInt64FromMap(data, "DispBegin", 0)),
				DispEnd:     int(common.GetInt64FromMap(data, "DispEnd", 0)),
				Status:      int(common.GetInt64FromMap(data, "Status", 0)),
				GmtCreated:  int(common.GetInt64FromMap(data, "GmtCreated", 0)),
				GmtUpdated:  int(common.GetInt64FromMap(data, "GmtUpdated", 0)),
				OpIp:        common.GetStringFromMap(data, "OpIp", ""),
			}
			gifts[i] = gift
		}
	}
	return gifts
}

// 将奖品的数据更新到缓存
func (s *giftService) setAllByCache(gifts []model.Gift) {
	// 集群模式，redis缓存
	strValue := ""
	if len(gifts) > 0 {
		datalist := make([]map[string]interface{}, len(gifts))
		// 格式转换
		for i := 0; i < len(gifts); i++ {
			gift := gifts[i]
			data := make(map[string]interface{})
			data["Id"] = gift.Id
			data["Name"] = gift.Name
			data["TotalCnt"] = gift.TotalCnt
			data["RemainCnt"] = gift.RemainCnt
			data["HitRate"] = gift.HitRate
			data["DurationDay"] = gift.DurationDay
			data["Img"] = gift.Img
			data["DispOrder"] = gift.DispOrder
			data["Type"] = gift.Type
			data["Data"] = gift.Data
			data["BeginTime"] = gift.BeginTime
			data["EndTime"] = gift.EndTime
			data["DispBegin"] = gift.DispBegin
			data["DispEnd"] = gift.DispEnd
			data["Status"] = gift.Status
			data["GmtCreated"] = gift.GmtCreated
			data["GmtUpdated"] = gift.GmtUpdated
			data["OpIp"] = gift.OpIp
			datalist[i] = data
		}
		str, err := json.Marshal(datalist)
		if err != nil {
			log.Println()
		}
		strValue = string(str)
	}
	key := "allgift"
	// 更新缓存
	_, err := datasource.G_redis.Do("SET", key, strValue)
	if err != nil {
		log.Println("gift_service.setAllByCache SET key=", key,
			", value=", strValue, ", error=", err)
	}
}

// 数据更新，需要更新缓存，直接清空缓存数据
func (s *giftService) updateByCache(data *model.Gift, columns []string) {
	if data == nil || data.Id <= 0 {
		return
	}
	// 集群模式，redis缓存
	key := "allgift"
	// 删除redis中的缓存
	_, _ = datasource.G_redis.Do("DEL", key)
}
